package cn.gxufe.reliable.message.api.controller;

import cn.gxufe.reliable.message.api.holder.MessageHolder;
import cn.gxufe.reliable.message.api.producer.TryServiceProducer;
import cn.gxufe.reliable.message.api.producer.MessageCallBackInterface;
import cn.gxufe.reliable.message.common.Message;
import cn.gxufe.reliable.message.common.ResultVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.sql.ResultSet;

/**
 * @author yingjie.rong
 **/
@RestController
@RequestMapping("/reliable/message")
public class ForProducerMessageController {

    private static final Logger logger = LoggerFactory.getLogger(ForProducerMessageController.class);

    @Autowired
    private MessageCallBackInterface messageCallBackService;

    @Autowired
    private TryServiceProducer tryService;

    private final static Integer ERROR_STATUS = -1;

    @Autowired
    private JdbcTemplate jdbcTemplate;


    @RequestMapping("/finish")
    @Transactional(rollbackFor = Throwable.class)
    public ResultVo finish(@RequestParam("messageId") Long messageId,
                           @RequestParam("key") String key,
                           @RequestParam("header") String header,
                           @RequestParam("finishData") String finishData){
        logger.info("finish : messageId = {} , key = {} , header = {} , finishData = {} ",messageId,key,header,finishData);
        Integer status = getStatus(key,messageId,header);
        if(ERROR_STATUS.equals(status)){
            return ResultVo.error(Message.RESPONSE_CODE_NOT_FOUNT,"not fount key = "+ key +"\t id = " + messageId+" value ");
        }
        if(status.equals(Message.STATUS_FINISH)) {
            logger.info( "id = {} , key = {} , status is finish", messageId,key );
            return ResultVo.ok("now value is finish !");
        }
        if( (status.equals(Message.STATUS_CONFIRM) )) {
            try {
                this.setStatusById(Message.STATUS_FINISH, key, status);
            }catch (Throwable t){
                return ResultVo.ok("now value is finish !");
            }
            ResultVo resultVo = messageCallBackService.finish(messageId, key, header, finishData);
            return resultVo;
        }
        return ResultVo.error(Message.RESPONSE_CODE_INCONSISTENT, String.valueOf(status));
    }


    @RequestMapping("/tryConfirm")
    @Transactional(rollbackFor = Throwable.class)
    public ResultVo tryConfirm(@RequestParam("messageId") Long messageId,
                               @RequestParam("key") String key,
                               @RequestParam("header") String header){
        logger.info("tryConfirm : messageId = {} , key = {} , header = {} ",messageId,key,header);
        return tryService.tryConfirm(messageId,key,header);
    }

    /**
     * 此时的转态是上游服务，下游服务执行失败，回调cancel接口
     * @param messageId
     * @param key
     * @param header
     * @param cancelData
     * @return
     */
    @RequestMapping("/cancel")
    @Transactional(rollbackFor = Throwable.class)
    public ResultVo cancel(@RequestParam("messageId") Long messageId,
                           @RequestParam("key") String key,
                           @RequestParam("header") String header,
                           @RequestParam("cancelData") String cancelData){
        logger.info("cancel : messageId = {} , key = {} , header = {} , cancelData = {} ",messageId,key,header,cancelData);
        Integer status = getStatus(key,messageId,header);
        if(ERROR_STATUS .equals(status)){
            return ResultVo.error(Message.RESPONSE_CODE_NOT_FOUNT,"not fount key = "+ key +"\t id = " + messageId+" value ");
        }
        if( status.equals( Message.STATUS_CANCEL) ){
            logger.info( "id = {} , key = {} , status is cancel", messageId,key );
            return ResultVo.ok("now value is cancel !");
        }
        if( status.equals( Message.STATUS_CONFIRM) || status.equals(Message.STATUS_PREPARE)){
            try {
                this.setStatusById(Message.STATUS_CANCEL,key ,status);
            }catch (Throwable t){
                return ResultVo.ok("now value is cancel !");
            }
            ResultVo resultVo = messageCallBackService.cancel(messageId, key, header, cancelData);
            return resultVo;
        }
        return ResultVo.error(Message.RESPONSE_CODE_INCONSISTENT, String.valueOf(status));
    }

    private Integer getStatus(String key,Long id ,String header){
        return jdbcTemplate.query("select `status`,`data`,`other` from reliable_message where `key` = ?", new Object[]{Message.SOURCE_SERVICE_KEY_PREFIX+key}, (ResultSet rs) ->  {
            if (rs.next()) {
                int anInt = rs.getInt(1);
                Message message = new Message();
                message.setKey(key);
                message.setData(rs.getString(2) );
                message.setId(id);
                message.setStatus(anInt);
                message.setHeader(header);
                MessageHolder.setValues( rs.getString(3));
                MessageHolder.setMessage(message);
                return anInt;
            }
            return ERROR_STATUS;
        });
    }

    private void setStatusById(int status,String key,int oldStatus){
        int rows = jdbcTemplate.update("update reliable_message set status = ? where status =? and `key` = ? ",
                status, oldStatus,Message.SOURCE_SERVICE_KEY_PREFIX+ key);
        if ( rows != 1 ){
            throw new RuntimeException("update status error, rows is not 1 !!");
        }
    }
}
